KM.Engine = function( iCanvas )
{
    this._canvas = iCanvas;
    this._renderer = null;
    this._scene = null;
    this._camera = null;
    this._ambientLight = null;
    
    this._OBJLoader = new KM.OBJLoader();
    this._teapot = null;
    
    this._onInitializedHandler = null;
    
    this._requestID = -1;
};

// Camera
KM.Engine.CAMERA_FOV = 70.0;
KM.Engine.CAMERA_NEAR = 1.0;
KM.Engine.CAMERA_FAR = 100.0;
KM.Engine.CAMERA_POSITION = [ 2.5, 2.5, 2.5 ];
KM.Engine.CAMERA_TARGET_POSITION = [ 0.0, 0.0, 0.0 ];
KM.Engine.CAMERA_TARGET_UP = [ 0.0, 1.0, 0.0 ];
// Ambient light
KM.Engine.AMBIENT_LIGHT_NAME = "KM_Ambient_Light";
KM.Engine.AMBIENT_LIGHT_COLOR = new KM.Color( 1.0, 1.0, 1.0 );
// Directional light
KM.Engine.DIRECTIONAL_LIGHT_NAME = "KM_Directional_Light";
KM.Engine.DIRECTIONAL_LIGHT_COLOR = new KM.Color( 1.0, 1.0, 1.0 );
// Teapot
KM.Engine.TEAPOT_URI = "assets/teapot.obj";
KM.Engine.TEAPOT_SCALE = [ 0.02, 0.02, 0.02 ];
KM.Engine.TEAPOT_MATERIAL_NAME = "KM_Teapot";
KM.Engine.TEAPOT_MATERIAL_EMISSIVE_COLOR = new KM.Color( 0.0, 0.0, 0.0 );
KM.Engine.TEAPOT_MATERIAL_AMBIENT_COLOR = new KM.Color( 0.3, 0.0, 0.0 );
KM.Engine.TEAPOT_MATERIAL_DIFFUSE_COLOR = new KM.Color( 0.5, 0.1, 0.1 );
KM.Engine.TEAPOT_MATERIAL_SPECULAR_COLOR = new KM.Color( 1.0, 1.0, 1.0 );
KM.Engine.TEAPOT_MATERIAL_ALPHA = 1.0;
KM.Engine.TEAPOT_NAME = "KM_Teapot";

KM.Engine.prototype = {
    constructor: KM.Engine,
    
    initRenderer: function()
    {
        this._renderer = new KM.Renderer( gl );
        this._renderer.init( this.onRendererReady.bind( this ) );
    },
    
    onRendererReady: function( iLoadedShadersCount )
    {
        console.log( "Engine.js, onRendererReady() : " + iLoadedShadersCount + " shaders have been loaded" );
        
        this.initScene();
        this.initCamera();
        this.initLights();
        this.initObjects();
    },
    
    initScene: function()
    {
        this._scene = new KM.Scene();
    },
    
    addObject3DToScene: function( iObject3D )
    {
        this._scene.add( iObject3D );
    },
    
    addLightToScene: function( iLight )
    {
        this._scene.addLight( iLight );
    },
    
    initCamera: function()
    {
        this._camera = new KM.Camera( this._canvas.width, this._canvas.height );
        this._camera.makePerspectiveProjection( KM.Engine.CAMERA_FOV, KM.Engine.CAMERA_NEAR, KM.Engine.CAMERA_FAR );
        this._camera.lookAt( KM.Engine.CAMERA_POSITION, KM.Engine.CAMERA_TARGET_POSITION, KM.Engine.CAMERA_TARGET_UP );
    },
    
    initLights: function()
    {
        // Ambient
        this._ambientLight = new KM.AmbientLight( KM.Engine.AMBIENT_LIGHT_NAME, KM.Engine.AMBIENT_LIGHT_COLOR );
        this.addLightToScene( this._ambientLight );
        
        // Directional
        var directionalLightDirection = vec3.create( [ -1.0, -1.0, -1.0 ] );
        vec3.scale( directionalLightDirection, -1 );
        vec3.normalize( directionalLightDirection );
        this._directionalLight = new KM.DirectionalLight( KM.Engine.DIRECTIONAL_LIGHT_NAME, KM.Engine.DIRECTIONAL_LIGHT_COLOR, directionalLightDirection );
        this.addLightToScene( this._directionalLight );
    },
    
    onObjectLoaded: function( iGeometry )
    {
        // Transform
        var teapotTransform = new KM.Transform();
        teapotTransform.scale( vec3.create( KM.Engine.TEAPOT_SCALE ) ); 
//        teapotTransform.translate( vec3.create( [ 0.0, 0, 0 ] ) );
    
        // Material
        var teapotMaterial = new KM.Material( KM.Engine.TEAPOT_MATERIAL_NAME,
            // Emissive
            KM.Engine.TEAPOT_MATERIAL_EMISSIVE_COLOR,
            // Ambient
            KM.Engine.TEAPOT_MATERIAL_AMBIENT_COLOR,
            // Diffuse
            KM.Engine.TEAPOT_MATERIAL_DIFFUSE_COLOR,
            // Specular
            KM.Engine.TEAPOT_MATERIAL_SPECULAR_COLOR,
            // Alpha
            KM.Engine.TEAPOT_MATERIAL_ALPHA );

        // Object3D
        this._teapot = new KM.Object3D( KM.Engine.TEAPOT_NAME, iGeometry, teapotTransform, teapotMaterial );
        this._teapot._shaderDescriptionName = shadersDescriptions[ 2 ].name;
        this.addObject3DToScene( this._teapot );
            
        // Callback
        this._onInitializedHandler();
    },
    
    onObjectLoadingProgress: function( iProgressPercent )
    {
//        console.log("Engine.js, onObjectLoadingProgress() : " + iProgressPercent + " %");
    },
    
    onObjectLoadingFailed: function( iError )
    {
        console.error("Engine.js, onObjectLoadingFailed() : " + iError);
    },
    
    initObjects: function()
    {
        this._OBJLoader.load( KM.Engine.TEAPOT_URI,
            this.onObjectLoaded.bind( this ),
            this.onObjectLoadingProgress.bind( this ),
            this.onObjectLoadingFailed.bind( this ) );
    },
    
    init: function( iCallback )
    {
        this._onInitializedHandler = iCallback;
        this.initRenderer();
    },
    
    start: function()
    {
        this._requestID = requestAnimFrame( this.update.bind( this ) );
    },
    
    update: function()
    {
        // Request next frame
        this._requestID = requestAnimFrame( this.update.bind( this ) );
        
        // Render
        this._renderer.render( this._scene, this._camera );
        
        // Stats
        stats.update();
    },
    
    stop: function()
    {
        cancelAnimationFrame( this._requestID );
        this._requestID = -1;
    }
};
